<!DOCTYPE html>
<html lang=zh>
<head>
    <meta charset="utf-8">
    
    <title>第十九章：使用JWT设计SpringBoot项目api接口安全服务 | 恒宇少年De成长之路</title>
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
    <meta name="description" content="JWT是一种用户双方之间传递安全信息的简洁的、URL安全的表述性声明规范。JWT（Json Web Token）作为一个开放的标准（RFC 7519），定义了一种简洁的、自包含的方法用于通信双方之间以Json对象的形式进行安全性信息传递，传递时有数字签名所以信息时安全的，JWT使用RSA公钥密钥的形式进行签名。">
<meta name="keywords" content="SpringBoot">
<meta property="og:type" content="article">
<meta property="og:title" content="第十九章：使用JWT设计SpringBoot项目api接口安全服务">
<meta property="og:url" content="http://blog.yuqiyu.com/spring-boot-chapter-19/index.html">
<meta property="og:site_name" content="恒宇少年De成长之路">
<meta property="og:description" content="JWT是一种用户双方之间传递安全信息的简洁的、URL安全的表述性声明规范。JWT（Json Web Token）作为一个开放的标准（RFC 7519），定义了一种简洁的、自包含的方法用于通信双方之间以Json对象的形式进行安全性信息传递，传递时有数字签名所以信息时安全的，JWT使用RSA公钥密钥的形式进行签名。">
<meta property="og:locale" content="zh-CN">
<meta property="og:image" content="http://upload-images.jianshu.io/upload_images/4461954-f3f1cb5d14004287.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:image" content="http://upload-images.jianshu.io/upload_images/4461954-9d3e5a1807973354.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:image" content="http://upload-images.jianshu.io/upload_images/4461954-e16c9bd7b1b94663.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:image" content="http://upload-images.jianshu.io/upload_images/4461954-a9bf16887793c7f8.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:image" content="http://upload-images.jianshu.io/upload_images/4461954-9e35fdb027533e64.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:image" content="http://upload-images.jianshu.io/upload_images/4461954-9969c3365544dec2.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:image" content="http://upload-images.jianshu.io/upload_images/4461954-04aa26c9efc14599.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:image" content="http://upload-images.jianshu.io/upload_images/4461954-7252b86190ac6cd9.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:image" content="http://upload-images.jianshu.io/upload_images/4461954-ab18e35dba6a1b81.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:image" content="http://upload-images.jianshu.io/upload_images/4461954-11dc50cfcdfb60d8.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:image" content="http://upload-images.jianshu.io/upload_images/4461954-dfd010f0edf0d7c4.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:image" content="http://upload-images.jianshu.io/upload_images/4461954-09a82f1972d67755.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:image" content="http://upload-images.jianshu.io/upload_images/4461954-b7ae406e7c635e87.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:image" content="http://upload-images.jianshu.io/upload_images/4461954-57539bcb533ee54a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:image" content="http://upload-images.jianshu.io/upload_images/4461954-22da2d2b1e38ef87.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:image" content="http://upload-images.jianshu.io/upload_images/4461954-0aa2a58cb51f681f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:image" content="http://upload-images.jianshu.io/upload_images/4461954-ea5c53b3a6e2f961.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:image" content="http://upload-images.jianshu.io/upload_images/4461954-057d93f260050c54.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:image" content="http://upload-images.jianshu.io/upload_images/4461954-7fb4c0f584f1ed9e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:image" content="http://upload-images.jianshu.io/upload_images/4461954-650be16b784db57f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:image" content="http://upload-images.jianshu.io/upload_images/4461954-56831053fd9d0d09.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:image" content="http://upload-images.jianshu.io/upload_images/4461954-3eefe2561540bfeb.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:image" content="http://upload-images.jianshu.io/upload_images/4461954-6e0edf3d590c3bed.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:image" content="http://upload-images.jianshu.io/upload_images/4461954-c502c1a1c4fd682b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:image" content="http://upload-images.jianshu.io/upload_images/4461954-cfb8901e53b08bbb.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:image" content="http://upload-images.jianshu.io/upload_images/4461954-32df2ffa886e2cc3.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:image" content="http://upload-images.jianshu.io/upload_images/4461954-5ba52cb1d89e4c1b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:image" content="http://upload-images.jianshu.io/upload_images/4461954-2e3ece62d204b1cb.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:updated_time" content="2018-02-21T08:02:18.081Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="第十九章：使用JWT设计SpringBoot项目api接口安全服务">
<meta name="twitter:description" content="JWT是一种用户双方之间传递安全信息的简洁的、URL安全的表述性声明规范。JWT（Json Web Token）作为一个开放的标准（RFC 7519），定义了一种简洁的、自包含的方法用于通信双方之间以Json对象的形式进行安全性信息传递，传递时有数字签名所以信息时安全的，JWT使用RSA公钥密钥的形式进行签名。">
<meta name="twitter:image" content="http://upload-images.jianshu.io/upload_images/4461954-f3f1cb5d14004287.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
    

    
        <link rel="alternate" href="/" title="恒宇少年De成长之路" type="application/atom+xml" />
    

    

    <link rel="stylesheet" href="/libs/font-awesome/css/font-awesome.min.css">
    <link rel="stylesheet" href="/libs/open-sans/styles.css">
    <link rel="stylesheet" href="/libs/source-code-pro/styles.css">

    <link rel="stylesheet" href="/css/style.css">

    <script src="/libs/jquery/2.1.3/jquery.min.js"></script>
    
    
        <link rel="stylesheet" href="/libs/lightgallery/css/lightgallery.min.css">
    
    
        <link rel="stylesheet" href="/libs/justified-gallery/justifiedGallery.min.css">
    
    
    
    


</head>

<body>
    <div id="container">
        <header id="header">
    <div id="header-main" class="header-inner">
        <div class="outer">
            <a href="/" id="logo">
                <i class="logo"></i>
                <span class="site-title">恒宇少年De成长之路</span>
            </a>
            <nav id="main-nav">
                
                    <a class="main-nav-link" href="/.">首页</a>
                
                    <a class="main-nav-link" href="/archives">时间轴</a>
                
                    <a class="main-nav-link" href="/categories">文章专题</a>
                
                    <a class="main-nav-link" href="/tags">标签云</a>
                
                    <a class="main-nav-link" href="/about">关于我</a>
                
            </nav>
            
                
                <nav id="sub-nav">
                    <div class="profile" id="profile-nav">
                        <a id="profile-anchor" href="javascript:;">
                            <img class="avatar" src="/css/images/avatar.png" />
                            <i class="fa fa-caret-down"></i>
                        </a>
                    </div>
                </nav>
            
            <div id="search-form-wrap">

    <form class="search-form">
        <input type="text" class="ins-search-input search-form-input" placeholder="搜索" />
        <!--button type="submit" class="search-form-submit"></button-->
    </form>
    <div class="ins-search">
    <div class="ins-search-mask"></div>
    <div class="ins-search-container">
        <div class="ins-input-wrapper">
            <input type="text" class="ins-search-input" placeholder="想要查找什么..." />
            <span class="ins-close ins-selectable"><i class="fa fa-times-circle"></i></span>
        </div>
        <div class="ins-section-wrapper">
            <div class="ins-section-container"></div>
        </div>
    </div>
</div>
<script>
(function (window) {
    var INSIGHT_CONFIG = {
        TRANSLATION: {
            POSTS: '文章',
            PAGES: '页面',
            CATEGORIES: '分类',
            TAGS: '标签',
            UNTITLED: '(未命名)',
        },
        ROOT_URL: '/',
        CONTENT_URL: '/content.json',
    };
    window.INSIGHT_CONFIG = INSIGHT_CONFIG;
})(window);
</script>
<script src="/js/insight.js"></script>

</div>
        </div>
    </div>
    <div id="main-nav-mobile" class="header-sub header-inner">
        <table class="menu outer">
            <tr>
                
                    <td ><a  class="main-nav-link" href="/.">首页</a></td>
                
                    <td ><a  class="main-nav-link" href="/archives">时间轴</a></td>
                
                    <td ><a  class="main-nav-link" href="/categories">文章专题</a></td>
                
                    <td ><a  class="main-nav-link" href="/tags">标签云</a></td>
                
                    <td ><a  class="main-nav-link" href="/about">关于我</a></td>
                
                <td>
                    
    <div class="search-form">
        <input type="text" class="ins-search-input search-form-input" placeholder="搜索" />
    </div>

                </td>
            </tr>
        </table>
    </div>
</header>

        <div class="outer">
            
                

<aside id="profile">
    <div class="inner profile-inner">
        <div class="base-info profile-block">
            <img id="avatar" src="/css/images/avatar.png" />
            <h2 id="name">恒宇少年</h2>
            <h3 id="title">Java软件工程师 &amp; 程序猿</h3>
            <span id="location"><i class="fa fa-map-marker"></i>山东, 济南</span>
            <a id="follow" target="_blank" href="https://www.jianshu.com/u/092df3f77bca">关注我</a>
        </div>
        <div class="article-info profile-block">
            <div class="article-info-block">
                43
                <span>文章</span>
            </div>
            <div class="article-info-block">
                2
                <span>标签</span>
            </div>
        </div>
        
        <div class="profile-block social-links">
            <table>
                <tr>
                    
                    
                    <td>
                        <a href="http://github.com/ppoffice/hexo-theme-icarus" target="_blank" title="github" class=tooltip>
                            <i class="fa fa-github"></i>
                        </a>
                    </td>
                    
                    <td>
                        <a href="/" target="_blank" title="twitter" class=tooltip>
                            <i class="fa fa-twitter"></i>
                        </a>
                    </td>
                    
                    <td>
                        <a href="/" target="_blank" title="facebook" class=tooltip>
                            <i class="fa fa-facebook"></i>
                        </a>
                    </td>
                    
                    <td>
                        <a href="/" target="_blank" title="dribbble" class=tooltip>
                            <i class="fa fa-dribbble"></i>
                        </a>
                    </td>
                    
                    <td>
                        <a href="/" target="_blank" title="rss" class=tooltip>
                            <i class="fa fa-rss"></i>
                        </a>
                    </td>
                    
                </tr>
            </table>
        </div>
        
    </div>
</aside>

            
            <section id="main"><article id="post-spring-boot-chapter-19" class="article article-type-post" itemscope itemprop="blogPost">
    <div class="article-inner">
        
        
            <header class="article-header">
                
    
        <h1 class="article-title" itemprop="name">
            第十九章：使用JWT设计SpringBoot项目api接口安全服务
        </h1>
    

                
                    <div class="article-meta">
                        
    <div class="article-date">
        <i class="fa fa-calendar"></i>
        <a href="/spring-boot-chapter-19/">
            <time datetime="2017-04-21T16:00:00.000Z" itemprop="datePublished">2017-04-22</time>
        </a>
    </div>


                        
    <div class="article-category">
    	<i class="fa fa-folder"></i>
        <a class="article-category-link" href="/categories/SpringBoot-核心技术/">SpringBoot 核心技术</a>
    </div>

                        
    <div class="article-tag">
        <i class="fa fa-tag"></i>
        <a class="tag-link" href="/tags/SpringBoot/">SpringBoot</a>
    </div>

                    </div>
                
            </header>
        
        
        <div class="article-entry" itemprop="articleBody">
        
            
            <p>JWT是一种用户双方之间传递安全信息的简洁的、URL安全的表述性声明规范。<code>JWT（Json Web Token）</code>作为一个开放的标准（RFC 7519），定义了一种简洁的、自包含的方法用于通信双方之间以Json对象的形式进行安全性信息传递，传递时有数字签名所以信息时安全的，JWT使用RSA公钥密钥的形式进行签名。<br><a id="more"></a></p>
<h1 id="JWT组成"><a href="#JWT组成" class="headerlink" title="JWT组成"></a>JWT组成</h1><p><code>JWT</code>格式的输出是以.分隔的三段<code>Base64</code>编码，与SAML等基于XML的标准相比，JWT在HTTP和HTML环境中更容易传递。（形式：xxxxx.yyy.zzz）：</p>
<p>1、<code>Header</code>：头部<br>2、<code>Payload</code>：负载<br>3、<code>Signature</code>：签名</p>
<h4 id="Header"><a href="#Header" class="headerlink" title="Header"></a>Header</h4><p>在header中通常包含了两部分，Token类型以及采用加密的算法</p>
<h4 id="Payload"><a href="#Payload" class="headerlink" title="Payload"></a>Payload</h4><p>Token的第二部分是负载，它包含了Claim，Claim是一些实体（一般都是用户）的状态和额外的数据组成。</p>
<h4 id="Signature"><a href="#Signature" class="headerlink" title="Signature"></a>Signature</h4><p>创建签名需要使用编码后的header和payload以及一个秘钥，使用header中指定签名算法进行签名。</p>
<h4 id="JWT工作流程图"><a href="#JWT工作流程图" class="headerlink" title="JWT工作流程图"></a>JWT工作流程图</h4><p>JWT客户端发送请求到服务器端整体流程如下图1所示：<br><img src="http://upload-images.jianshu.io/upload_images/4461954-f3f1cb5d14004287.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="图1"></p>
<h1 id="本章目标"><a href="#本章目标" class="headerlink" title="本章目标"></a>本章目标</h1><p>在SpringBoot项目中使用JWT作为接口安全框架，实现JWT生成以及验证。</p>
<h1 id="构建项目"><a href="#构建项目" class="headerlink" title="构建项目"></a>构建项目</h1><p>我们使用InteiiJ IDEA工具来构建一个SpringBoot项目，预先导入依赖<code>Web、JPA、MySQL</code>等，项目结构如下图2所示：<br><img src="http://upload-images.jianshu.io/upload_images/4461954-9d3e5a1807973354.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="图2"></p>
<h4 id="添加JWT依赖"><a href="#添加JWT依赖" class="headerlink" title="添加JWT依赖"></a>添加JWT依赖</h4><p>目前JWT支持多中变成语言，我们访问官网<a href="https://jwt.io/" target="_blank" rel="noopener"><code>jwt.io/</code></a>，在首页底部可以看到JWT所支持的所有编程语言以及对应的依赖包，我们选择<code>io.jsonwebtoken（GitHub地址：[github.com/jwtk/jjwt](https://github.com/jwtk/jjwt)）</code>，目前已经更新到<code>0.7.0</code>版本了，我们添加最新的依赖到我们的pom.xml配置文件中，如下图3所示：<br><img src="http://upload-images.jianshu.io/upload_images/4461954-e16c9bd7b1b94663.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="图3"></p>
<p>我们只需要导入红框内的依赖即可，下面我们开始添加对应的数据库表结构。</p>
<h1 id="数据库配置"><a href="#数据库配置" class="headerlink" title="数据库配置"></a>数据库配置</h1><p>我们将生成的Token存放到数据库中，要完成一整套的验证我们需要存储用户基本信息、Token基本信息两张表。</p>
<h4 id="用户基本信息表"><a href="#用户基本信息表" class="headerlink" title="用户基本信息表"></a>用户基本信息表</h4><p><img src="http://upload-images.jianshu.io/upload_images/4461954-a9bf16887793c7f8.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="图4"></p>
<p>可以看到上图4就是我们的用户信息表内的所有字段，其中我们可以添加自定义的字段如：ajax_bind_ip（ajax请求时绑定的客户端的IP地址）。</p>
<h4 id="Token基本信息表"><a href="#Token基本信息表" class="headerlink" title="Token基本信息表"></a>Token基本信息表</h4><p><img src="http://upload-images.jianshu.io/upload_images/4461954-9e35fdb027533e64.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="图5"></p>
<p>我们保存的Token在数据库中是byte字节的形式存在，根据对应的appId生成一个Token。</p>
<h4 id="application-yml"><a href="#application-yml" class="headerlink" title="application.yml"></a>application.yml</h4><p>我们复制之前章节（<a href="http://www.jianshu.com/p/9d5bf0e4943f" target="_blank" rel="noopener">第十三章：SpringBoot实战SpringDataJPA</a>，文章底部源码链接）的application.yml配置文件到本章项目的resources目录下，如下图6所示：<br><img src="http://upload-images.jianshu.io/upload_images/4461954-9969c3365544dec2.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="图6"></p>
<h4 id="添加Druid依赖"><a href="#添加Druid依赖" class="headerlink" title="添加Druid依赖"></a>添加Druid依赖</h4><p>修改pom.xml配置文件添加Druid的maven依赖，如下图7所示：<br><img src="http://upload-images.jianshu.io/upload_images/4461954-04aa26c9efc14599.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="图7"></p>
<h4 id="创建用户实体"><a href="#创建用户实体" class="headerlink" title="创建用户实体"></a>创建用户实体</h4><p>我们根据数据库内的用户基本信息表的字段构建出一个UserEntity，如下图8所示：<br><img src="http://upload-images.jianshu.io/upload_images/4461954-7252b86190ac6cd9.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="图8"></p>
<h4 id="创建Token实体"><a href="#创建Token实体" class="headerlink" title="创建Token实体"></a>创建Token实体</h4><p>根据token基本信息表内的字段构建出TokenEntity实体，如下图9所示：<br><img src="http://upload-images.jianshu.io/upload_images/4461954-ab18e35dba6a1b81.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="图9"></p>
<p>我们实体创建完成后对应实体添加JPA，用于SpringDataJPA操作数据表信息。</p>
<h4 id="创建UserJPA"><a href="#创建UserJPA" class="headerlink" title="创建UserJPA"></a>创建UserJPA</h4><p><img src="http://upload-images.jianshu.io/upload_images/4461954-11dc50cfcdfb60d8.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="图10"></p>
<h4 id="创建TokenJPA"><a href="#创建TokenJPA" class="headerlink" title="创建TokenJPA"></a>创建TokenJPA</h4><p><img src="http://upload-images.jianshu.io/upload_images/4461954-dfd010f0edf0d7c4.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="图11"></p>
<h1 id="生成Token"><a href="#生成Token" class="headerlink" title="生成Token"></a>生成Token</h1><p>我们的准备工作已经做完，下面开始实现生成Token的控制器，我们先来创建一个TokenController，如下图12所示：<br><img src="http://upload-images.jianshu.io/upload_images/4461954-09a82f1972d67755.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="图12"></p>
<p>在编写获取Token的方法之前需要添加一个试图返回的类，方便我们在编写获取Token方法返回数据，如下图13所示：<br><img src="http://upload-images.jianshu.io/upload_images/4461954-b7ae406e7c635e87.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="图13"></p>
<p>我们在TokenController控制器内添加获取Token的方法，如下图14、15、16、17、18所示：<br><img src="http://upload-images.jianshu.io/upload_images/4461954-57539bcb533ee54a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="图14"><br><img src="http://upload-images.jianshu.io/upload_images/4461954-22da2d2b1e38ef87.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="图15"><br><img src="http://upload-images.jianshu.io/upload_images/4461954-0aa2a58cb51f681f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="图16"><br><img src="http://upload-images.jianshu.io/upload_images/4461954-ea5c53b3a6e2f961.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="图17"><br><img src="http://upload-images.jianshu.io/upload_images/4461954-057d93f260050c54.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="图18"></p>
<p>生成Token的方法比较长，所以还是建议下载源码查看，源码链接在文章底部。</p>
<blockquote>
<p>生成Token方法的内容大致是，检查appId以及appSecret–&gt;检查是否存在该appId的对应Token–&gt;根据存在与否、过期与否执行更新或者写入操作–&gt;返回用户请求。</p>
</blockquote>
<p>在createNewToken方法中是JWT生成Token的方法，我们默认了过期时间为7200秒，上面是毫秒单位，我们生成token需要指定subject也就是我们的用户对象，设置过期时间、生成时间、还有签名生成规则等。token生成方法已经编写完成，下面我们需要在除了获取token的路径排除在外拦截所有的路径，验证路径是否存在header包含token，并且验证token是否正确，jwt会自动给我们验证过期，如果过期会抛出对应的异常。</p>
<h1 id="Token验证拦截器"><a href="#Token验证拦截器" class="headerlink" title="Token验证拦截器"></a>Token验证拦截器</h1><p>我们在拦截器中需要验证头信息，Token的值是否存在，Subject用户是否存在等。具体代码如下图19、20所示：<br><img src="http://upload-images.jianshu.io/upload_images/4461954-7fb4c0f584f1ed9e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="图19"><br><img src="http://upload-images.jianshu.io/upload_images/4461954-650be16b784db57f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="图20"></p>
<p>Claims就是我们生成Token是的对象，我们把传递的头信息token通过JWT可以逆转成Claims对象，并且通过getSubject可以获取到我们用户的appId。</p>
<h4 id="配置拦截器"><a href="#配置拦截器" class="headerlink" title="配置拦截器"></a>配置拦截器</h4><p>我们创建一个JWTConfiguration配置类，将我们创建的拦截器添加到SpringBoot项目中，如下图21所示：<br><img src="http://upload-images.jianshu.io/upload_images/4461954-56831053fd9d0d09.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="图21"></p>
<p><code>注意：我们配置JWT拦截器只拦截/api/下的所有路径。</code></p>
<h1 id="运行测试"><a href="#运行测试" class="headerlink" title="运行测试"></a>运行测试</h1><p>在启动项目之前我们先来配置一个IndexController，并且提供一个访问内容的API接口，如下图22所示：<br><img src="http://upload-images.jianshu.io/upload_images/4461954-3eefe2561540bfeb.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="图22"></p>
<p>下面我们来启动项目，访问地址：<a href="http://127.0.0.1:8080/api/index" target="_blank" rel="noopener">127.0.0.1:8080/api/index</a>，界面输出内容如下图23所示：<br><img src="http://upload-images.jianshu.io/upload_images/4461954-6e0edf3d590c3bed.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="图23"></p>
<p>我们在拦截器中配置的无论是不存在token还是token需要刷新都是返回”need refresh token”错误信息，下面我们在我们的用户信息表内添加一条测试数据，如下图24所示：<br><img src="http://upload-images.jianshu.io/upload_images/4461954-c502c1a1c4fd682b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="图24"></p>
<p>其中密码也是使用到了byte字节的形式保存，具体内容我会放到项目源码resources目录下！下面我们通过/token地址获取jwt生成的token值，如下图25所示：<br><img src="http://upload-images.jianshu.io/upload_images/4461954-cfb8901e53b08bbb.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="图25"></p>
<p>可以看到我们可以正确的获取到JWT生成的token值，我们来看下是否存到数据库中。如下图26所示：<br><img src="http://upload-images.jianshu.io/upload_images/4461954-32df2ffa886e2cc3.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="图26"></p>
<p>可以看到我们数据库中已经有一条生成的Token值保存了，接下来我们使用获取到的Token通过Postman工具来访问我们的/api/index方法，如下图27所示：<br><img src="http://upload-images.jianshu.io/upload_images/4461954-5ba52cb1d89e4c1b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="图27"></p>
<p>可以看到我们将之前获取的token作为请求header（X-YAuth-Token）的值进行传递，再次访问<a href="http://127.0.0.1:8080/api/index" target="_blank" rel="noopener">127.0.0.1:8080/api/index</a>，就可以成功的获取接口返回的数据。</p>
<blockquote>
<p>注意：如果Token过期，再次访问/jwt/token地址传入对应的appId以及appSecret就可以获取一条新的token，也会对应的更新数据库token信息表的内容。</p>
</blockquote>
<h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><p>以上内容就是本章的全部讲解内容，本章主要讲解了SpringBoot项目如何加入JWT维护接口安全性，并且将JWT生成的Token存放到数据库中。</p>
<p>本章代码已经上传到码云：</p>
<p>SpringBoot配套源码地址：<a href="https://gitee.com/hengboy/spring-boot-chapter" target="_blank" rel="noopener">https://gitee.com/hengboy/spring-boot-chapter</a></p>
<p>SpringCloud配套源码地址：<a href="https://gitee.com/hengboy/spring-cloud-chapter" target="_blank" rel="noopener">https://gitee.com/hengboy/spring-cloud-chapter</a></p>
<p>SpringBoot相关系列文章请访问：<a href="http://www.jianshu.com/p/9a08417e4e84" target="_blank" rel="noopener">目录：SpringBoot学习目录</a></p>
<p>QueryDSL相关系列文章请访问：<a href="http://www.jianshu.com/p/99a5ec5c3bd5" target="_blank" rel="noopener">QueryDSL通用查询框架学习目录</a></p>
<p>SpringDataJPA相关系列文章请访问：<a href="http://www.jianshu.com/p/615ed9c1fe84" target="_blank" rel="noopener">目录：SpringDataJPA学习目录</a></p>
<p>SpringBoot相关文章请访问：<a href="http://www.jianshu.com/p/9a08417e4e84" target="_blank" rel="noopener">目录：SpringBoot学习目录</a>，感谢阅读！</p>
<p>欢迎加入QQ技术交流群，共同进步。<br><img src="http://upload-images.jianshu.io/upload_images/4461954-2e3ece62d204b1cb.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="QQ技术交流群"></p>

        
        </div>
        <footer class="article-footer">
            <div class="share-container">


    <div class="bdsharebuttonbox">
    <a href="#" class="bds_more" data-cmd="more">分享到：</a>
    <a href="#" class="bds_qzone" data-cmd="qzone" title="分享到QQ空间">QQ空间</a>
    <a href="#" class="bds_tsina" data-cmd="tsina" title="分享到新浪微博">新浪微博</a>
    <a href="#" class="bds_tqq" data-cmd="tqq" title="分享到腾讯微博">腾讯微博</a>
    <a href="#" class="bds_renren" data-cmd="renren" title="分享到人人网">人人网</a>
    <a href="#" class="bds_weixin" data-cmd="weixin" title="分享到微信">微信</a>
</div>
<script>
window._bd_share_config={"common":{"bdSnsKey":{},"bdText":"","bdMini":"2","bdMiniList":false,"bdPic":"","bdStyle":"0","bdSize":"16"},"share":{"bdSize":16}};with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('script')).src='http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion='+~(-new Date()/36e5)];
</script>
<style>
    .bdshare_popup_box {
        border-radius: 4px;
        border: #e1e1e1 solid 1px;
    }
    .bdshare-button-style0-16 a,
    .bdshare-button-style0-16 .bds_more {
        padding-left: 20px;
        margin: 6px 10px 6px 0;
    }
    .bdshare_dialog_list a,
    .bdshare_popup_list a,
    .bdshare_popup_bottom a {
        font-family: 'Microsoft Yahei';
    }
    .bdshare_popup_top {
        display: none;
    }
    .bdshare_popup_bottom {
        height: auto;
        padding: 5px;
    }
</style>


</div>

            
    

        </footer>
    </div>
    
        
<nav id="article-nav">
    
        <a href="/spring-boot-chapter-20/" id="article-nav-newer" class="article-nav-link-wrap">
            <strong class="article-nav-caption">上一篇</strong>
            <div class="article-nav-title">
                
                    第二十章：SpringBoot项目中使用WebSocket配置广播式通信
                
            </div>
        </a>
    
    
        <a href="/spring-boot-chapter-18/" id="article-nav-older" class="article-nav-link-wrap">
            <strong class="article-nav-caption">下一篇</strong>
            <div class="article-nav-title">第十八章：SpringBoot项目中使用SpringSecurity整合OAuth2设计项目API安全接口服务</div>
        </a>
    
</nav>


    
</article>


    
    

</section>
            
			
				
<aside id="sidebar">
   
        
    <div class="widget-wrap">
        <h3 class="widget-title">最新文章</h3>
        <div class="widget">
            <ul id="recent-post" class="no-thumbnail">
                
                    <li>
                        
                        <div class="item-inner">
                            <p class="item-category"><a class="article-category-link" href="/categories/SpringBoot-核心技术/">SpringBoot 核心技术</a></p>
                            <p class="item-title"><a href="/spring-boot-chapter-52/" class="title">第五十二章：基于SpringBoot2使用Rest访问MongoDB数据</a></p>
                            <p class="item-date"><time datetime="2018-04-21T16:00:00.000Z" itemprop="datePublished">2018-04-22</time></p>
                        </div>
                    </li>
                
                    <li>
                        
                        <div class="item-inner">
                            <p class="item-category"><a class="article-category-link" href="/categories/SpringBoot-核心技术/">SpringBoot 核心技术</a></p>
                            <p class="item-title"><a href="/spring-boot-chapter-51/" class="title">第五十一章：基于SpringBoot2 &amp; MongoDB完成自动化集成</a></p>
                            <p class="item-date"><time datetime="2018-04-15T16:00:00.000Z" itemprop="datePublished">2018-04-16</time></p>
                        </div>
                    </li>
                
                    <li>
                        
                        <div class="item-inner">
                            <p class="item-category"><a class="article-category-link" href="/categories/SpringBoot-核心技术/">SpringBoot 核心技术</a></p>
                            <p class="item-title"><a href="/spring-boot-chapter-50/" class="title">第五十章：SpringBoot2.0新特性 - 岂止至今最简单redis缓存集成</a></p>
                            <p class="item-date"><time datetime="2018-04-14T16:00:00.000Z" itemprop="datePublished">2018-04-15</time></p>
                        </div>
                    </li>
                
                    <li>
                        
                        <div class="item-inner">
                            <p class="item-category"><a class="article-category-link" href="/categories/SpringBoot-核心技术/">SpringBoot 核心技术</a></p>
                            <p class="item-title"><a href="/spring-boot-chapter-49/" class="title">第四十九章：SpringBoot2.0新特性 - 你get到WebMvcConfigurer两种配置方式了吗？</a></p>
                            <p class="item-date"><time datetime="2018-03-16T16:00:00.000Z" itemprop="datePublished">2018-03-17</time></p>
                        </div>
                    </li>
                
                    <li>
                        
                        <div class="item-inner">
                            <p class="item-category"><a class="article-category-link" href="/categories/SpringBoot-核心技术/">SpringBoot 核心技术</a></p>
                            <p class="item-title"><a href="/spring-boot-chapter-48/" class="title">第四十八章：SpringBoot2.0新特性 - RabbitMQ信任package设置</a></p>
                            <p class="item-date"><time datetime="2018-03-12T16:00:00.000Z" itemprop="datePublished">2018-03-13</time></p>
                        </div>
                    </li>
                
            </ul>
        </div>
    </div>

    
        
    <div class="widget-wrap">
        <h3 class="widget-title">分类</h3>
        <div class="widget">
            <ul class="category-list"><li class="category-list-item"><a class="category-list-link" href="/categories/QueryDSL-核心技术/">QueryDSL 核心技术</a><span class="category-list-count">7</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/SpringBoot-核心技术/">SpringBoot 核心技术</a><span class="category-list-count">36</span></li></ul>
        </div>
    </div>

    
        
    <div class="widget-wrap">
        <h3 class="widget-title">归档</h3>
        <div class="widget">
            <ul class="archive-list"><li class="archive-list-item"><a class="archive-list-link" href="/archives/2018/04/">四月 2018</a><span class="archive-list-count">3</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2018/03/">三月 2018</a><span class="archive-list-count">4</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2018/01/">一月 2018</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2017/12/">十二月 2017</a><span class="archive-list-count">4</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2017/11/">十一月 2017</a><span class="archive-list-count">2</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2017/10/">十月 2017</a><span class="archive-list-count">2</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2017/09/">九月 2017</a><span class="archive-list-count">4</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2017/08/">八月 2017</a><span class="archive-list-count">4</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2017/07/">七月 2017</a><span class="archive-list-count">9</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2017/06/">六月 2017</a><span class="archive-list-count">2</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2017/05/">五月 2017</a><span class="archive-list-count">3</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2017/04/">四月 2017</a><span class="archive-list-count">5</span></li></ul>
        </div>
    </div>

    
        
    <div class="widget-wrap">
        <h3 class="widget-title">标签</h3>
        <div class="widget">
            <ul class="tag-list"><li class="tag-list-item"><a class="tag-list-link" href="/tags/QueryDSL/">QueryDSL</a><span class="tag-list-count">7</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/SpringBoot/">SpringBoot</a><span class="tag-list-count">43</span></li></ul>
        </div>
    </div>

    
        
    <div class="widget-wrap">
        <h3 class="widget-title">标签云</h3>
        <div class="widget tagcloud">
            <a href="/tags/QueryDSL/" style="font-size: 10px;">QueryDSL</a> <a href="/tags/SpringBoot/" style="font-size: 20px;">SpringBoot</a>
        </div>
    </div>

    
        
    <div class="widget-wrap widget-list">
        <h3 class="widget-title">链接</h3>
        <div class="widget">
            <ul>
                
                    <li>
     				<a href="http://hexo.io" target="_blank">Hexo</a>
					</li>
                
            </ul>
        </div>
    </div>


    
    <div id="toTop" class="fa fa-angle-up"></div>
</aside>

				
        </div>
        <!--引入不蒜子-->
<script async src="//dn-lbstatics.qbox.me/busuanzi/2.3/busuanzi.pure.mini.js"></script>
<footer id="footer">
    <div class="outer">
        <div id="footer-info" class="inner">
            <span  id="busuanzi_container_site_pv">本站总访问量<span id="busuanzi_value_site_pv"></span>次</span>
            &copy; 2017 - 2018 恒宇少年 - 版权所有<br>
        </div>
    </div>
</footer>

        


    
        <script src="/libs/lightgallery/js/lightgallery.min.js"></script>
        <script src="/libs/lightgallery/js/lg-thumbnail.min.js"></script>
        <script src="/libs/lightgallery/js/lg-pager.min.js"></script>
        <script src="/libs/lightgallery/js/lg-autoplay.min.js"></script>
        <script src="/libs/lightgallery/js/lg-fullscreen.min.js"></script>
        <script src="/libs/lightgallery/js/lg-zoom.min.js"></script>
        <script src="/libs/lightgallery/js/lg-hash.min.js"></script>
        <script src="/libs/lightgallery/js/lg-share.min.js"></script>
        <script src="/libs/lightgallery/js/lg-video.min.js"></script>
    
    
        <script src="/libs/justified-gallery/jquery.justifiedGallery.min.js"></script>
    
    



<!-- Custom Scripts -->
<script src="/js/main.js"></script>

    </div>
</body>
</html>